Autor: Patryk Wittbrodt
WZ_INIS6 50933

Zadanie 1¶

Link do źródła danych: https://www.kaggle.com/sanjeetsinghnaik/football-data-top-5-leagues

Liga której dotyczy moja praca: Bundesliga
Dane dotyczą okresu 2016-2020

In [ ]:
# import bibliotek i wczytanie danych z pliku .csv

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.ticker
import plotly.offline

plotly.offline.init_notebook_mode() # aby zapisać wykresy utworzone za pomocą plotly

plt.style.use('seaborn')
sns.set(font_scale=1)
sns.set(rc={'figure.figsize':(11.7,8.27)})

df = pd.read_csv('bundesliga.csv')

Zestawienie nr 1: Ilość oddanych strzałów oraz strzelonych bramek przez konkretną drużynę w okresie 2016-2020 (alfabetycznie)¶

Jako, że drużyny grają jako gospodarze i goście, trzeba będzie uwzlędnić to w programie.

In [ ]:
df1 = df.copy() # użycie copy jest bezpieczniejsze - mamy pewność, że nie nadpiszemy oryginału.

dataShotsGoals = df1[['Home Team', 'Away Team', 'Home Team Total Shots', 'Away Team Total Shots', 'Home Team Goals Scored', 'Away Team Goals Scored']].copy()

# Aby podsumować bramki strzelone przez daną drużynę trzeba uwzględnić strzelone zarówno w domu, jak i na wyjeździe.
dataShotsGoals_home = df1[['Home Team', 'Home Team Total Shots', 'Home Team Goals Scored']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Total Shots': 'Strzały', 'Home Team Goals Scored': 'Bramki' })
dataShotsGoals_away = df1[['Away Team', 'Away Team Total Shots', 'Away Team Goals Scored']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Total Shots': 'Strzały', 'Away Team Goals Scored': 'Bramki' })

# Informacje potrzebne do wykresu nr 3
dataShotsGoals_home['Teren'] = 'U siebie'
dataShotsGoals_away['Teren'] = 'Wyjazdowy'

# Aby złączyć tablice należy użyć .concat().
dataShotsGoals_cat = pd.concat([dataShotsGoals_home, dataShotsGoals_away])
dataShotsGoals_cat['Strzały'] = dataShotsGoals_cat['Strzały'].astype(int) # zmieniamy typ wyświetlanych danych na int, ponieważ domyślnie jest typ zmiennoprzecinkowy, co w tym przypadku nie ma sensu.

# Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
sortedShotsGoals = dataShotsGoals_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn.

chart1Data = sortedShotsGoals.copy() # dane potrzebne do pierwszego wykresu, kopia dokonana jest w tym momencie, ponieważ na wykresie nie będziemy potrzebować danych o skuteczności.

sortedShotsGoals['Skuteczność (%)'] = (sortedShotsGoals['Bramki'] / sortedShotsGoals['Strzały'] * 100).round(2) # wyliczenie skuteczności, czyli stosunku bramek do oddanych strzałów.
sortedShotsGoals
Out[ ]:
Drużyna Strzały Bramki Skuteczność (%)
0 1. FC KÖLN 1524 171 11.22
1 AUGSBURG 1958 210 10.73
2 BAYERN 3058 468 15.30
3 BIELEFELD 335 26 7.76
4 DARMSTADT 341 28 8.21
5 DORTMUND 2404 376 15.64
6 DÜSSELDORF 846 85 10.05
7 FRANKFURT 2141 269 12.56
8 FREIBURG 2053 220 10.72
9 HANNOVER 820 75 9.15
10 HERTHA 1814 224 12.35
11 HOFFENHEIM 2466 305 12.37
12 HSV 755 62 8.21
13 INGOLSTADT 455 36 7.91
14 LEVERKUSEN 2410 294 12.20
15 M'GLADBACH 2260 277 12.26
16 MAINZ 2159 211 9.77
17 NÜRNBERG 360 26 7.22
18 PADERBORN 431 37 8.58
19 RB LEIPZIG 2519 327 12.98
20 SCHALKE 1951 198 10.15
21 STUTTGART 1229 124 10.09
22 UNION BERLIN 800 91 11.38
23 W. BREMEN 2070 234 11.30
24 WOLFSBURG 2164 241 11.14

Zestawienie nr 2: Najbardziej faulujące drużyny oraz ilość i rodzaj kartek jakimi zostały ukarane.¶

Ranking najbardziej faulujących drużyn.

In [ ]:
df2 = df.copy()

dataFouls = df2[['Home Team', 'Away Team', 'Home Team Fouls', 'Away Team Fouls', 'Home Team Yellow Cards', 'Away Team Yellow Cards', 'Home Team Red Cards', 'Away Team Red Cards']].copy()

# Tak jak poprzednio, dzielimy bazę na gospodarzy i gości, aby potem ją połączyć i zebrać poprawnie dane.
dataFouls_home = df2[['Home Team', 'Home Team Fouls', 'Home Team Yellow Cards', 'Home Team Red Cards']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Fouls': 'Faule', 'Home Team Yellow Cards': 'Żółte kartki', 'Home Team Red Cards': 'Czerwone kartki' })
dataFouls_away = df2[['Away Team', 'Away Team Fouls', 'Away Team Yellow Cards', 'Away Team Red Cards']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Fouls': 'Faule', 'Away Team Yellow Cards': 'Żółte kartki', 'Away Team Red Cards': 'Czerwone kartki' })

# Aby złączyć tablice należy użyć .concat().
dataFouls_cat = pd.concat([dataFouls_home, dataFouls_away])

# Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
groupedFouls = dataFouls_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn
sortedFouls = groupedFouls.sort_values(by='Faule', ascending=False) # chcemy sortować od największych do najmniejszych ilości, dlatego ascending ustawiamy na False

sortedFouls['Faule'] = sortedFouls['Faule'].astype(int)
sortedFouls['Żółte kartki'] = sortedFouls['Żółte kartki'].astype(int)
sortedFouls['Czerwone kartki'] = sortedFouls['Czerwone kartki'].astype(int)

sortedFouls
Out[ ]:
Drużyna Faule Żółte kartki Czerwone kartki
16 MAINZ 2418 322 6
7 FRANKFURT 2367 365 10
10 HERTHA 2357 318 8
20 SCHALKE 2325 341 9
11 HOFFENHEIM 2316 332 4
23 W. BREMEN 2291 324 3
24 WOLFSBURG 2249 314 6
19 RB LEIPZIG 2249 280 5
1 AUGSBURG 2216 324 4
14 LEVERKUSEN 2122 275 8
8 FREIBURG 2069 267 4
15 M'GLADBACH 1968 273 2
0 1. FC KÖLN 1860 281 3
5 DORTMUND 1772 227 6
2 BAYERN 1677 227 4
21 STUTTGART 1255 185 4
12 HSV 1063 135 4
22 UNION BERLIN 955 124 3
9 HANNOVER 908 124 1
6 DÜSSELDORF 839 145 1
13 INGOLSTADT 555 72 3
4 DARMSTADT 515 71 0
18 PADERBORN 426 82 1
17 NÜRNBERG 394 58 3
3 BIELEFELD 390 52 1

Zestawienie nr 3: 10 najbardziej ekscytujących meczów w 2020 roku¶

Na podstawie "Match Excitement"

In [ ]:
df3 = df[df['year']==2020].copy()

df3 = df3[['Home Team', 'Away Team', 'Score', 'Match Excitement']].rename(columns={'Home Team': 'Drużyna gospodarzy', 'Away Team': 'Drużyna gości', 'Score': "Wynik końcowy", 'Match Excitement': 'Poziom ekscytacji (0-10)'})
sortedByExcitement = df3.sort_values(by='Poziom ekscytacji (0-10)', ascending=False)
sortedByExcitement.head(10)
Out[ ]:
Drużyna gospodarzy Drużyna gości Wynik końcowy Poziom ekscytacji (0-10)
1287 HOFFENHEIM STUTTGART 3-3 10.0
1516 SCHALKE FRANKFURT 4-3 10.0
1250 BAYERN HERTHA 4-3 10.0
1286 LEVERKUSEN M'GLADBACH 4-3 9.8
1468 FRANKFURT WOLFSBURG 4-3 9.8
1262 MAINZ M'GLADBACH 2-3 9.7
1411 BAYERN BIELEFELD 3-3 9.5
1527 BAYERN AUGSBURG 5-2 9.4
1348 BAYERN MAINZ 5-2 9.2
1225 1. FC KÖLN HOFFENHEIM 2-3 9.1

Zestawienie nr 4: Średnie posiadanie piłki i rezultaty spotkań poszczególnych drużyn w 2016 roku¶

Dane ze wszystkich lat mogłyby zaburzyć wnioski - nie wszystkie drużyny się utrzymały w Bundeslidze, przez co ich ilośc spotkań i wygranych meczów byłaby znacznie niższa.

Wniosek: Drużyny, które mają większe posiadanie piłki wygrywają więcej spotkań.

In [ ]:
df4 = df[df['year']==2016].copy() # użycie copy jest bezpieczniejsze - mamy pewność, że nie nadpiszemy oryginału.

dataPossession = df4[['Home Team', 'Away Team', 'Home Team Possession %', 'Away Team Possession %', 'Home Team Goals Scored', 'Away Team Goals Scored']].copy()
dataPossession.reset_index() # resetujemy indeksy, aby przeprowadzić iteracje

# tworzymy nowe dane o rezultacie spotkań na podstawie ilości bramek
dataPossession['Home Wins'] = np.where(dataPossession['Home Team Goals Scored'] > dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Home Loses'] = np.where(dataPossession['Home Team Goals Scored'] < dataPossession['Away Team Goals Scored'], 1, 0)

dataPossession['Home Draws'] = np.where(dataPossession['Home Team Goals Scored'] == dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Away Draws'] = np.where(dataPossession['Home Team Goals Scored'] == dataPossession['Away Team Goals Scored'], 1, 0)

dataPossession['Away Loses'] = np.where(dataPossession['Home Team Goals Scored'] > dataPossession['Away Team Goals Scored'], 1, 0)
dataPossession['Away Wins'] = np.where(dataPossession['Home Team Goals Scored'] < dataPossession['Away Team Goals Scored'], 1, 0)

dataPossession_home = dataPossession[['Home Team', 'Home Team Possession %', 'Home Wins', 'Home Draws', 'Home Loses']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Possession %': 'Posiadanie piłki (%)', 'Home Wins': 'Wygrane', 'Home Draws': 'Remisy', 'Home Loses': 'Przegrane' })
dataPossession_away = dataPossession[['Away Team', 'Away Team Possession %', 'Away Wins', 'Away Draws', 'Away Loses']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Possession %': 'Posiadanie piłki (%)', 'Away Wins': 'Wygrane', 'Away Draws': 'Remisy', 'Away Loses': 'Przegrane' })

# Aby złączyć tablice należy użyć .concat().
dataPossession_cat = pd.concat([dataPossession_home, dataPossession_away])

# # Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
groupedPossession = dataPossession_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn.
sortedPossession = groupedPossession.sort_values(by='Posiadanie piłki (%)', ascending=False) # chcemy sortować od największych do najmniejszych ilości, dlatego ascending ustawiamy na False

# wyliczenie ilości rozegranych spotkań, która wynosi 34 dla wszystkich drużyn (dla pewności i łatwego wyliczenia średniego posiadania piłki)
# sortedPossession['Ilość rozegranych meczów'] = (sortedPossession['Wygrane'] + sortedPossession['Remisy'] + sortedPossession['Przegrane'])

sortedPossession['Posiadanie piłki (%)'] = (sortedPossession['Posiadanie piłki (%)'] / 34).round(2) # dzielimy sumę procentów posiadania piłki przez ilość rozegranych spotkań

sortedPossession
Out[ ]:
Drużyna Posiadanie piłki (%) Wygrane Remisy Przegrane
2 BAYERN 68.91 25 7 2
4 DORTMUND 62.00 18 10 6
8 HOFFENHEIM 56.24 16 14 4
11 LEVERKUSEN 54.18 11 8 15
12 M'GLADBACH 53.85 12 9 13
14 RB LEIPZIG 52.97 20 7 7
15 SCHALKE 51.71 11 10 13
17 WOLFSBURG 51.62 10 7 17
5 FRANKFURT 49.88 11 9 14
7 HERTHA 48.50 15 4 15
6 FREIBURG 46.68 14 6 14
10 INGOLSTADT 45.97 8 8 18
13 MAINZ 45.88 10 7 17
16 W. BREMEN 44.56 13 6 15
9 HSV 43.74 10 8 16
0 1. FC KÖLN 43.32 12 13 9
1 AUGSBURG 41.76 9 11 14
3 DARMSTADT 38.24 7 4 23

Zestawienie nr 5: Procent udanych podań i rezultaty spotkań poszczególnych drużyn w 2018 roku¶

Zestawienie bardzo podobne do poprzedniego, jednak warte uwagi.

Wniosek: Drużyny, których podania kończą się częściej sukcesem wygrywają więcej spotkań.

In [ ]:
df5 = df[df['year']==2018].copy() # użycie copy jest bezpieczniejsze - mamy pewność, że nie nadpiszemy oryginału.

dataPassSuccess = df5[['Home Team', 'Away Team', 'Home Team Pass Success %', 'Away Team Pass Success %', 'Home Team Goals Scored', 'Away Team Goals Scored']].copy()
dataPassSuccess.reset_index() # resetujemy indeksy, aby przeprowadzić iteracje

# tworzymy nowe dane o rezultacie spotkań na podstawie ilości bramek
dataPassSuccess['Home Wins'] = np.where(dataPassSuccess['Home Team Goals Scored'] > dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Home Loses'] = np.where(dataPassSuccess['Home Team Goals Scored'] < dataPassSuccess['Away Team Goals Scored'], 1, 0)

dataPassSuccess['Home Draws'] = np.where(dataPassSuccess['Home Team Goals Scored'] == dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Away Draws'] = np.where(dataPassSuccess['Home Team Goals Scored'] == dataPassSuccess['Away Team Goals Scored'], 1, 0)

dataPassSuccess['Away Loses'] = np.where(dataPassSuccess['Home Team Goals Scored'] > dataPassSuccess['Away Team Goals Scored'], 1, 0)
dataPassSuccess['Away Wins'] = np.where(dataPassSuccess['Home Team Goals Scored'] < dataPassSuccess['Away Team Goals Scored'], 1, 0)

dataPassSuccess_home = dataPassSuccess[['Home Team', 'Home Team Pass Success %', 'Home Wins', 'Home Draws', 'Home Loses']].copy().rename(columns={'Home Team': 'Drużyna', 'Home Team Pass Success %': 'Udane podania (%)', 'Home Wins': 'Wygrane', 'Home Draws': 'Remisy', 'Home Loses': 'Przegrane' })
dataPassSuccess_away = dataPassSuccess[['Away Team', 'Away Team Pass Success %', 'Away Wins', 'Away Draws', 'Away Loses']].copy().rename(columns={'Away Team': 'Drużyna', 'Away Team Pass Success %': 'Udane podania (%)', 'Away Wins': 'Wygrane', 'Away Draws': 'Remisy', 'Away Loses': 'Przegrane' })

# Aby złączyć tablice należy użyć .concat().
dataPassSuccess_cat = pd.concat([dataPassSuccess_home, dataPassSuccess_away])

# # Na koniec wystarczy posortować względem drużyny, dodać kolumnę gdzie będzie liczona skuteczność i wyświetlić wynik końcowy.
groupedPassSuccess = dataPassSuccess_cat.groupby('Drużyna').sum().reset_index() # grupujemy nasz wynik likwidując duplikaty drużyn.
sortedPassSuccess = groupedPassSuccess.sort_values(by='Udane podania (%)', ascending=False) # chcemy sortować od największych do najmniejszych ilości, dlatego ascending ustawiamy na False

# wyliczenie ilości rozegranych spotkań, która wynosi 34 dla wszystkich drużyn (dla pewności i łatwego wyliczenia średniego posiadania piłki)
# sortedPassSuccess['Ilość rozegranych meczów'] = (sortedPassSuccess['Wygrane'] + sortedPassSuccess['Remisy'] + sortedPassSuccess['Przegrane'])

sortedPassSuccess['Udane podania (%)'] = (sortedPassSuccess['Udane podania (%)'] / 34).round(2) # dzielimy sumę procentów posiadania piłki przez ilość rozegranych spotkań

sortedPassSuccess
Out[ ]:
Drużyna Udane podania (%) Wygrane Remisy Przegrane
1 BAYERN 87.06 24 6 4
2 DORTMUND 85.21 23 7 4
10 M'GLADBACH 83.53 16 7 11
9 LEVERKUSEN 83.12 18 4 12
8 HOFFENHEIM 81.32 13 12 9
16 W. BREMEN 79.06 14 11 9
17 WOLFSBURG 78.26 16 7 11
7 HERTHA 77.71 11 10 13
5 FREIBURG 76.76 8 12 14
11 MAINZ 76.38 12 7 15
3 DÜSSELDORF 76.06 13 5 16
6 HANNOVER 75.85 5 6 23
14 SCHALKE 75.41 8 9 17
12 NÜRNBERG 74.91 3 10 21
15 STUTTGART 74.68 7 7 20
13 RB LEIPZIG 74.65 19 9 6
0 AUGSBURG 73.53 8 8 18
4 FRANKFURT 72.35 15 9 10

Wykres nr 1: Bramki i strzały w 2016-2020¶

Wniosek: Bardzo mało strzałów kończy się bramką, dlatego bramki w tym sporcie są tak wyjątkowe.

In [ ]:
# Aby pokazać strzały i bramki na tym samym wykresie musimy zmienić układ danych za pomocą .melt()

chart1Data_melt = pd.melt(chart1Data, id_vars=['Drużyna'], value_vars=['Strzały', 'Bramki'], var_name="Rodzaj", value_name="Wartość")

ax1 = sns.barplot(x="Drużyna", y="Wartość", hue="Rodzaj", data=chart1Data_melt)
ax1.set_xticklabels(ax1.get_xticklabels(), rotation=90)
ax1.set_title('Bramki i strzały w 2016-2020')
None # dzięki temu unikamy wyjścia w formie tekstowej

Wykres nr 2: Oceny gospodarzy vs oceny gości w konkretnych latach¶

Wniosek: Gospodarze zazwyczaj lepiej wypadają w spotkaniach.

In [ ]:
chart2Data = df.groupby(by=['year'])

disp2 = chart2Data.mean() # wyliczamy średnią wartość dla kolumn znajdujących się w zestawie

fig, ax2 = plt.subplots(figsize=(10,8))
ax2.plot(chart2Data['Home Team Rating'].mean(), marker='.', label='Gospodarze')
ax2.plot(chart2Data['Away Team Rating'].mean(), marker='.', label='Goście')

# Rok wyświetlał się niepoprawnie (zamiast 2016 było 2016.0) przez co trzeba było rozwiązać to w następujący sposób:
locator = matplotlib.ticker.MultipleLocator(1) # przesunięcie na osi x
plt.gca().xaxis.set_major_locator(locator)
plt.xlim([2016, 2020]) # ustalenie granic wykresu na osi x

plt.xlabel("Rok")
plt.ylabel("Wartość oceny (0-10)")
plt.title("Oceny gospodarzy vs oceny gości w konkretnych latach")
plt.legend()
None # dzięki temu unikamy wyjścia w formie tekstowej

Wykres nr 3: Strzały oddane przez drużyny względem miejsca spotkania¶

Wniosek: Zawodnicy na swoim terenie oddają więcej strzałów co świadczy o tym, że są pewniejsi siebie, grają agresywniej.

In [ ]:
plt.figure(figsize=(15,5))
ax3 = sns.barplot(x="Drużyna", y="Strzały", hue="Teren", data=dataShotsGoals_cat, ci=0) # dane z zestawienia nr 1
ax3.set_xticklabels(ax3.get_xticklabels(), rotation=90)
ax3.set_title('Strzały oddane przez drużyny względem miejsca spotkania')
None # dzięki temu unikamy wyjścia w formie tekstowej

Wykres nr 4: Dane dotyczące rodzajów strzałów w lidze na przestrzeni lat 2016-2020¶

In [ ]:
chart4Data = df[['Home Team Off Target Shots', 'Home Team On Target Shots', 'Home Team Blocked Shots', 'Away Team Off Target Shots', 'Away Team On Target Shots', 'Away Team Blocked Shots']].copy()

chart4Data_home = chart4Data[['Home Team Off Target Shots', 'Home Team On Target Shots', 'Home Team Blocked Shots']].copy().rename(columns={'Home Team Off Target Shots': 'Strzały niecelne', 'Home Team On Target Shots': "Strzały celne", 'Home Team Blocked Shots': 'Strzały zablokowane' })
chart4Data_away = chart4Data[['Away Team Off Target Shots', 'Away Team On Target Shots', 'Away Team Blocked Shots']].copy().rename(columns={'Away Team Off Target Shots': 'Strzały niecelne', 'Away Team On Target Shots': 'Strzały celne', 'Away Team Blocked Shots': 'Strzały zablokowane' })

chart4Data_cat = pd.concat([chart4Data_home, chart4Data_away]).sum()

labels = ['Strzały niecelne','Strzały celne','Strzały zablokowane']
values = [chart4Data_cat['Strzały niecelne'], chart4Data_cat['Strzały celne'], chart4Data_cat['Strzały zablokowane']]
 
fig4 = px.pie(values=values, names=labels, color_discrete_sequence=px.colors.sequential.Blackbody, width=800, height=400, title='Dane dotyczące rodzajów strzałów w Bundeslidze na przestrzeni lat 2016-2020')

fig4.show()

Wykres nr 5: Dane dotyczące fauli i kar dla drużyn na przestrzeni lat 2016-2020¶

Wniosek: Zdecydowana większość przewinień nie jest karana, natomiast czerwone kartki to wyjątkowa rzadkość.

In [ ]:
chart5Data = df[['Home Team Fouls', 'Home Team Yellow Cards', 'Home Team Red Cards', 'Away Team Fouls', 'Away Team Yellow Cards', 'Away Team Red Cards']].copy()

chart5Data_home = chart5Data[['Home Team Fouls', 'Home Team Yellow Cards', 'Home Team Red Cards']].copy().rename(columns={'Home Team Fouls': 'Faule bez kary', 'Home Team Yellow Cards': "Żółte kartki", 'Home Team Red Cards': 'Czerwone kartki' })
chart5Data_away = chart5Data[['Away Team Fouls', 'Away Team Yellow Cards', 'Away Team Red Cards']].copy().rename(columns={'Away Team Fouls': 'Faule bez kary', 'Away Team Yellow Cards': "Żółte kartki", 'Away Team Red Cards': 'Czerwone kartki' })

chart5Data_cat = pd.concat([chart5Data_home, chart5Data_away]).sum()
# jako, że 'Fouls' w zestawie danych to suma wszystkich fauli, należy obliczyć faule bez kary odejmując od sumy wszystkich faule zakończone karą
chart5Data_cat['Faule bez kary'] = chart5Data_cat['Faule bez kary'] - (chart5Data_cat['Żółte kartki'] + chart5Data_cat['Czerwone kartki'])

labels = ['Faule bez kary','Żółte kartki','Czerwone kartki']
values = [chart5Data_cat['Faule bez kary'], chart5Data_cat['Żółte kartki'], chart5Data_cat['Czerwone kartki']]
 
fig5 = px.pie(values=values, names=labels, color_discrete_sequence=px.colors.sequential.Emrld, width=800, height=400, title='Dane dotyczące fauli i kar dla drużyn w Bundeslidze na przestrzeni lat 2016-2020')

fig5.show()